package pushtest.mobike.com.mtpush.ui.behavior;

import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
import android.support.annotation.RestrictTo.Scope;
import android.support.annotation.VisibleForTesting;
import android.support.design.R.dimen;
import android.support.design.R.styleable;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.CoordinatorLayout.Behavior;
import android.support.v4.math.MathUtils;
import android.support.v4.view.AbsSavedState;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v4.widget.ViewDragHelper.Callback;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import timber.log.Timber;

public class MyTestBehaivor<V extends View> extends Behavior<V> {

  public static final int STATE_DRAGGING = 1;
  public static final int STATE_SETTLING = 2;
  public static final int STATE_EXPANDED = 3;
  public static final int STATE_COLLAPSED = 4;
  public static final int STATE_HIDDEN = 5;
  public static final int STATE_HALF_EXPANDED = 6;
  public static final int PEEK_HEIGHT_AUTO = -1;
  private static final float HIDE_THRESHOLD = 0.5F;
  private static final float HIDE_FRICTION = 0.1F;
  private boolean fitToContents = true;
  private float maximumVelocity;
  private float minVelocity;
  private int peekHeight;
  private boolean peekHeightAuto;
  private int peekHeightMin;
  private int lastPeekHeight;
  private int fitToContentsOffset;
  private int halfExpandedOffset;
  private int collapsedOffset;
  private boolean hideable;
  private boolean skipCollapsed;
  private int state = STATE_COLLAPSED;
  private ViewDragHelper viewDragHelper;
  private boolean ignoreEvents;
  private int lastNestedScrollDy;
  private boolean nestedScrolled;
  private int parentHeight;
  WeakReference viewRef;
  WeakReference<View> nestedScrollingChildRef;
  private MyTestBehaivor.BottomSheetCallback callback;
  private VelocityTracker velocityTracker;
  private int activePointerId;
  private int initialY;
  private boolean touchingScrollingChild;
  private Map<View, Integer> importantForAccessibilityMap;
  private final Callback dragCallback = new Callback() {
    public boolean tryCaptureView(@NonNull View child, int pointerId) {
      if (MyTestBehaivor.this.state == STATE_DRAGGING) {
        return false;
      } else if (MyTestBehaivor.this.touchingScrollingChild) {
        return false;
      } else {
        if (MyTestBehaivor.this.state == STATE_EXPANDED
            && MyTestBehaivor.this.activePointerId == pointerId) {
          View scroll = (View) MyTestBehaivor.this.nestedScrollingChildRef.get();
          if (scroll != null && scroll.canScrollVertically(-1)) {
            return false;
          }
        }

        return MyTestBehaivor.this.viewRef != null
            && MyTestBehaivor.this.viewRef.get() == child;
      }
    }

    public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx,
        int dy) {
      MyTestBehaivor.this.dispatchOnSlide(top);
    }

    public void onViewDragStateChanged(int state) {
      if (state == STATE_DRAGGING) {
        MyTestBehaivor.this.setStateInternal(STATE_DRAGGING);
      }

    }

    public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
      int top;
      byte targetState;
      int currentTop;
      if (yvel < 0.0F) {
        if (MyTestBehaivor.this.fitToContents) {
          top = MyTestBehaivor.this.fitToContentsOffset;
          targetState = STATE_EXPANDED;
        } else {
          currentTop = releasedChild.getTop();
          if (currentTop > MyTestBehaivor.this.halfExpandedOffset) {
            top = MyTestBehaivor.this.halfExpandedOffset;
            targetState = STATE_HALF_EXPANDED;
          } else {
            top = 0;
            targetState = STATE_EXPANDED;
          }
        }
      } else if (!MyTestBehaivor.this.hideable || !MyTestBehaivor.this
          .shouldHide(releasedChild, yvel)
          || releasedChild.getTop() <= MyTestBehaivor.this.collapsedOffset
          && Math.abs(xvel) >= Math.abs(yvel)) {
        if (yvel != 0.0F && Math.abs(xvel) <= Math.abs(yvel)) {
          top = MyTestBehaivor.this.collapsedOffset;
          targetState = STATE_COLLAPSED;
        } else {
          currentTop = releasedChild.getTop();
          if (MyTestBehaivor.this.fitToContents) {
            if (Math.abs(currentTop - MyTestBehaivor.this.fitToContentsOffset) < Math
                .abs(currentTop - MyTestBehaivor.this.collapsedOffset)) {
              top = MyTestBehaivor.this.fitToContentsOffset;
              targetState = STATE_EXPANDED;
            } else {
              top = MyTestBehaivor.this.collapsedOffset;
              targetState = STATE_COLLAPSED;
            }
          } else if (currentTop < MyTestBehaivor.this.halfExpandedOffset) {
            if (currentTop < Math.abs(currentTop - MyTestBehaivor.this.collapsedOffset)) {
              top = 0;
              targetState = STATE_EXPANDED;
            } else {
              top = MyTestBehaivor.this.halfExpandedOffset;
              targetState = STATE_HALF_EXPANDED;
            }
          } else if (Math.abs(currentTop - MyTestBehaivor.this.halfExpandedOffset) < Math
              .abs(currentTop - MyTestBehaivor.this.collapsedOffset)) {
            top = MyTestBehaivor.this.halfExpandedOffset;
            targetState = STATE_HALF_EXPANDED;
          } else {
            top = MyTestBehaivor.this.collapsedOffset;
            targetState = STATE_COLLAPSED;
          }
        }
      } else {
        top = MyTestBehaivor.this.parentHeight;
        targetState = STATE_HIDDEN;
      }

      if (MyTestBehaivor.this.viewDragHelper
          .settleCapturedViewAt(releasedChild.getLeft(), top)) {
        MyTestBehaivor.this.setStateInternal(STATE_SETTLING);
        ViewCompat.postOnAnimation(releasedChild,
            MyTestBehaivor.this.new SettleRunnable(releasedChild, targetState));
      } else {
        MyTestBehaivor.this.setStateInternal(targetState);
      }

    }

    public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
      Timber.e("top $top");
      return MathUtils.clamp(top, MyTestBehaivor.this.getExpandedOffset(),
          MyTestBehaivor.this.hideable ? MyTestBehaivor.this.parentHeight
              : MyTestBehaivor.this.collapsedOffset);
    }

    public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
      return child.getLeft();
    }

    public int getViewVerticalDragRange(@NonNull View child) {
      return MyTestBehaivor.this.hideable ? MyTestBehaivor.this.parentHeight
          : MyTestBehaivor.this.collapsedOffset;
    }
  };

  public MyTestBehaivor() {
  }

  public MyTestBehaivor(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, styleable.BottomSheetBehavior_Layout);
    TypedValue value = a.peekValue(styleable.BottomSheetBehavior_Layout_behavior_peekHeight);
    if (value != null && value.data == PEEK_HEIGHT_AUTO) {
      this.setPeekHeight(value.data);
    } else {
      this.setPeekHeight(
          a.getDimensionPixelSize(styleable.BottomSheetBehavior_Layout_behavior_peekHeight,
              PEEK_HEIGHT_AUTO));
    }

    this.setHideable(a.getBoolean(styleable.BottomSheetBehavior_Layout_behavior_hideable, false));
    this.setFitToContents(
        a.getBoolean(styleable.BottomSheetBehavior_Layout_behavior_fitToContents, true));
    this.setSkipCollapsed(
        a.getBoolean(styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed, false));
    a.recycle();
    ViewConfiguration configuration = ViewConfiguration.get(context);
    this.maximumVelocity = (float) configuration.getScaledMaximumFlingVelocity();
    this.minVelocity = configuration.getScaledMinimumFlingVelocity();
  }

  public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
    return new MyTestBehaivor.SavedState(super.onSaveInstanceState(parent, child), this.state);
  }

  public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
    MyTestBehaivor.SavedState ss = (MyTestBehaivor.SavedState) state;
    super.onRestoreInstanceState(parent, child, ss.getSuperState());
    if (ss.state != STATE_DRAGGING && ss.state != STATE_SETTLING) {
      this.state = ss.state;
    } else {
      this.state = STATE_COLLAPSED;
    }

  }

  public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
    if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
      child.setFitsSystemWindows(true);
    }

    int savedTop = child.getTop();
    parent.onLayoutChild(child, layoutDirection);
    this.parentHeight = parent.getHeight();
    if (this.peekHeightAuto) {
      if (this.peekHeightMin == 0) {
        this.peekHeightMin = parent.getResources()
            .getDimensionPixelSize(dimen.design_bottom_sheet_peek_height_min);
      }

      this.lastPeekHeight = Math
          .max(this.peekHeightMin, this.parentHeight - parent.getWidth() * 9 / 16);
    } else {
      this.lastPeekHeight = this.peekHeight;
    }

    this.fitToContentsOffset = Math.max(0, this.parentHeight - child.getHeight());
    this.halfExpandedOffset = this.parentHeight / STATE_SETTLING;
    this.calculateCollapsedOffset();
    if (this.state == STATE_EXPANDED) {
      ViewCompat.offsetTopAndBottom(child, this.getExpandedOffset());
    } else if (this.state == STATE_HALF_EXPANDED) {
      ViewCompat.offsetTopAndBottom(child, this.halfExpandedOffset);
    } else if (this.hideable && this.state == STATE_HIDDEN) {
      ViewCompat.offsetTopAndBottom(child, this.parentHeight);
    } else if (this.state == STATE_COLLAPSED) {
      ViewCompat.offsetTopAndBottom(child, this.collapsedOffset);
    } else if (this.state == STATE_DRAGGING || this.state == STATE_SETTLING) {
      ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
    }

    if (this.viewDragHelper == null) {
      this.viewDragHelper = ViewDragHelper.create(parent, this.dragCallback);
    }

    this.viewRef = new WeakReference(child);
    this.nestedScrollingChildRef = new WeakReference(this.findScrollingChild(child));
    return true;
  }

  public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
    if (!child.isShown()) {
      this.ignoreEvents = true;
      return false;
    } else {
      int action = event.getActionMasked();
      if (action == 0) {
        this.reset();
      }

      if (this.velocityTracker == null) {
        this.velocityTracker = VelocityTracker.obtain();
      }

      this.velocityTracker.addMovement(event);
      switch (action) {
        case 0:
          int initialX = (int) event.getX();
          this.initialY = (int) event.getY();
          View scroll =
              this.nestedScrollingChildRef != null ? (View) this.nestedScrollingChildRef.get()
                  : null;
          if (scroll != null && parent.isPointInChildBounds(scroll, initialX, this.initialY)) {
            this.activePointerId = event.getPointerId(event.getActionIndex());
            this.touchingScrollingChild = true;
          }

          this.ignoreEvents = this.activePointerId == -1 && !parent
              .isPointInChildBounds(child, initialX, this.initialY);
          break;
        case 1:
        case 3:
          this.touchingScrollingChild = false;
          this.activePointerId = -1;
          if (this.ignoreEvents) {
            this.ignoreEvents = false;
            return false;
          }
        case ACTION_MOVE:
      }

      if (!this.ignoreEvents && this.viewDragHelper != null && this.viewDragHelper
          .shouldInterceptTouchEvent(event)) {
        return true;
      } else {
        View scroll =
            this.nestedScrollingChildRef != null ? (View) this.nestedScrollingChildRef.get() : null;
        return action == ACTION_MOVE && scroll != null && !this.ignoreEvents
            && this.state != STATE_DRAGGING && !parent
            .isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY())
            && this.viewDragHelper != null
            && Math.abs((float) this.initialY - event.getY()) > (float) this.viewDragHelper
            .getTouchSlop();
      }
    }
  }

  public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
    if (!child.isShown()) {
      return false;
    } else {
      int action = event.getActionMasked();
      if (this.state == STATE_DRAGGING && action == ACTION_DOWN) {
        return true;
      } else {
        if (this.viewDragHelper != null) {
          this.viewDragHelper.processTouchEvent(event);
        }

        if (action == 0) {
          this.reset();
        }

        if (this.velocityTracker == null) {
          this.velocityTracker = VelocityTracker.obtain();
        }

        this.velocityTracker.addMovement(event);
        if (action == STATE_SETTLING && !this.ignoreEvents
            && Math.abs((float) this.initialY - event.getY()) > (float) this.viewDragHelper
            .getTouchSlop()) {
          this.viewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));
        }

        return !this.ignoreEvents;
      }
    }
  }

  public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
      @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
    this.lastNestedScrollDy = 0;
    this.nestedScrolled = false;
    return (axes & STATE_SETTLING) != 0;
  }

  public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
      @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
    if (type != STATE_DRAGGING) {
      View scrollingChild = (View) this.nestedScrollingChildRef.get();
      if (target == scrollingChild) {
        int currentTop = child.getTop();
        int newTop = currentTop - dy;
        if (dy > 0) {
          if (newTop < this.getExpandedOffset()) {
            consumed[STATE_DRAGGING] = currentTop - this.getExpandedOffset();
            ViewCompat.offsetTopAndBottom(child, -consumed[STATE_DRAGGING]);
            this.setStateInternal(STATE_EXPANDED);
          } else {
            consumed[STATE_DRAGGING] = dy;
            ViewCompat.offsetTopAndBottom(child, -dy);
            this.setStateInternal(STATE_DRAGGING);
          }
        } else if (dy < 0 && !target.canScrollVertically(-STATE_DRAGGING)) {
          if (newTop > this.collapsedOffset && !this.hideable) {
            consumed[STATE_DRAGGING] = currentTop - this.collapsedOffset;
            ViewCompat.offsetTopAndBottom(child, -consumed[STATE_DRAGGING]);
            this.setStateInternal(STATE_COLLAPSED);
          } else {
            consumed[STATE_DRAGGING] = dy;
            ViewCompat.offsetTopAndBottom(child, -dy);
            this.setStateInternal(STATE_DRAGGING);
          }
        }

        this.dispatchOnSlide(child.getTop());
        this.lastNestedScrollDy = dy;
        this.nestedScrolled = true;
      }
    }
  }

  public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
      @NonNull View target, int type) {
    if (child.getTop() == this.getExpandedOffset()) {
      this.setStateInternal(STATE_EXPANDED);
    } else if (target == this.nestedScrollingChildRef.get() && this.nestedScrolled) {
      int top;
      byte targetState;
      if (this.lastNestedScrollDy > 0) {
        top = this.getExpandedOffset();
        targetState = STATE_EXPANDED;
      } else if (this.hideable && this.shouldHide(child, this.getYVelocity())) {
        top = this.parentHeight;
        targetState = STATE_HIDDEN;
      } else if (this.lastNestedScrollDy == 0) {
        int currentTop = child.getTop();
        if (this.fitToContents) {
          if (Math.abs(currentTop - this.fitToContentsOffset) < Math
              .abs(currentTop - this.collapsedOffset)) {
            top = this.fitToContentsOffset;
            targetState = STATE_EXPANDED;
          } else {
            top = this.collapsedOffset;
            targetState = STATE_COLLAPSED;
          }
        } else if (currentTop < this.halfExpandedOffset) {
          if (currentTop < Math.abs(currentTop - this.collapsedOffset)) {
            top = 0;
            targetState = STATE_EXPANDED;
          } else {
            top = this.halfExpandedOffset;
            targetState = STATE_HALF_EXPANDED;
          }
        } else if (Math.abs(currentTop - this.halfExpandedOffset) < Math
            .abs(currentTop - this.collapsedOffset)) {
          top = this.halfExpandedOffset;
          targetState = STATE_HALF_EXPANDED;
        } else {
          top = this.collapsedOffset;
          targetState = STATE_COLLAPSED;
        }
      } else {
        top = this.collapsedOffset;
        targetState = STATE_COLLAPSED;
      }
      Timber.i(" velocity = %s", getYVelocity());
      if (Math.abs(getYVelocity()) > minVelocity * STATE_SETTLING && this.viewDragHelper
          .smoothSlideViewTo(child, child.getLeft(), top)) {
        this.setStateInternal(STATE_SETTLING);
        ViewCompat
            .postOnAnimation(child, new MyTestBehaivor.SettleRunnable(child, targetState));
      } else {
        if (Math.abs(getYVelocity()) <= minVelocity * STATE_SETTLING) {
          targetState = STATE_COLLAPSED;
        }
        this.setStateInternal(targetState);
      }

      this.nestedScrolled = false;
    }
  }

  public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
      @NonNull View target, float velocityX, float velocityY) {
    return target == this.nestedScrollingChildRef.get() && (this.state != STATE_EXPANDED || super
        .onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY));

  }

  public boolean isFitToContents() {
    return this.fitToContents;
  }

  public void setFitToContents(boolean fitToContents) {
    if (this.fitToContents != fitToContents) {
      this.fitToContents = fitToContents;
      if (this.viewRef != null) {
        this.calculateCollapsedOffset();
      }

      this.setStateInternal(
          this.fitToContents && this.state == STATE_HALF_EXPANDED ? STATE_EXPANDED : this.state);
    }
  }

  public final void setPeekHeight(int peekHeight) {
    boolean layout = false;
    if (peekHeight == PEEK_HEIGHT_AUTO) {
      if (!this.peekHeightAuto) {
        this.peekHeightAuto = true;
        layout = true;
      }
    } else if (this.peekHeightAuto || this.peekHeight != peekHeight) {
      this.peekHeightAuto = false;
      this.peekHeight = Math.max(0, peekHeight);
      this.collapsedOffset = this.parentHeight - peekHeight;
      layout = true;
    }

    if (layout && this.state == STATE_COLLAPSED && this.viewRef != null) {
      V view = (V) this.viewRef.get();
      if (view != null) {
        view.requestLayout();
      }
    }

  }

  public final int getPeekHeight() {
    return this.peekHeightAuto ? -1 : this.peekHeight;
  }

  public final int getFitToContentsOffset() {
    return fitToContentsOffset;
  }

  public final int getCollapsedOffset() {
    return this.collapsedOffset;
  }

  public final int getContextHeight() {
    return parentHeight - peekHeight;
  }

  public void setHideable(boolean hideable) {
    this.hideable = hideable;
  }

  public boolean isHideable() {
    return this.hideable;
  }

  public void setSkipCollapsed(boolean skipCollapsed) {
    this.skipCollapsed = skipCollapsed;
  }

  public boolean getSkipCollapsed() {
    return this.skipCollapsed;
  }

  public void setBottomSheetCallback(MyTestBehaivor.BottomSheetCallback callback) {
    this.callback = callback;
  }

  public final void setState(final int state) {
    if (state != this.state) {
      if (this.viewRef == null) {
        if (state == STATE_COLLAPSED || state == STATE_EXPANDED || state == STATE_HALF_EXPANDED
            || this.hideable && state == STATE_HIDDEN) {
          this.state = state;
        }

      } else {
        final V child = (V) this.viewRef.get();
        if (child != null) {
          ViewParent parent = child.getParent();
          if (parent != null && parent.isLayoutRequested() && ViewCompat
              .isAttachedToWindow(child)) {
            child.post(new Runnable() {
              public void run() {
                MyTestBehaivor.this.startSettlingAnimation(child, state);
              }
            });
          } else {
            this.startSettlingAnimation(child, state);
          }

        }
      }
    }
  }

  public final int getState() {
    return this.state;
  }

  void setStateInternal(int state) {
    if (this.state != state) {
      this.state = state;
           if (state != STATE_HALF_EXPANDED && state != STATE_EXPANDED) {
        if (state == STATE_HIDDEN || state == STATE_COLLAPSED) {
          this.updateImportantForAccessibility(false);
        }
      } else {
        this.updateImportantForAccessibility(true);
      }

      View bottomSheet = (View) this.viewRef.get();
      if (bottomSheet != null && this.callback != null) {
        this.callback.onStateChanged(bottomSheet, state);
      }

    }
  }

  private void calculateCollapsedOffset() {
    if (this.fitToContents) {
      this.collapsedOffset = Math
          .max(this.parentHeight - this.lastPeekHeight, this.fitToContentsOffset);
    } else {
      this.collapsedOffset = this.parentHeight - this.lastPeekHeight;
    }

  }

  private void reset() {
    this.activePointerId = -1;
    if (this.velocityTracker != null) {
      this.velocityTracker.recycle();
      this.velocityTracker = null;
    }

  }

  boolean shouldHide(View child, float yvel) {
    if (this.skipCollapsed) {
      return true;
    } else if (child.getTop() < this.collapsedOffset) {
      return false;
    } else {
      float newTop = (float) child.getTop() + yvel * HIDE_FRICTION;
      return Math.abs(newTop - (float) this.collapsedOffset) / (float) this.peekHeight
          > HIDE_THRESHOLD;
    }
  }

  @VisibleForTesting
  private View findScrollingChild(View view) {
    if (ViewCompat.isNestedScrollingEnabled(view)) {
      return view;
    } else {
      if (view instanceof ViewGroup) {
        ViewGroup group = (ViewGroup) view;
        int i = 0;

        for (int count = group.getChildCount(); i < count; ++i) {
          View scrollingChild = this.findScrollingChild(group.getChildAt(i));
          if (scrollingChild != null) {
            return scrollingChild;
          }
        }
      }

      return null;
    }
  }

  private float getYVelocity() {
    if (this.velocityTracker == null) {
      return 0.0F;
    } else {
      this.velocityTracker.computeCurrentVelocity(100, this.maximumVelocity);
      return this.velocityTracker.getYVelocity(this.activePointerId);
    }
  }

  private int getExpandedOffset() {
    return this.fitToContents ? this.fitToContentsOffset : 0;
  }

  void startSettlingAnimation(View child, int state) {
    int top;
    if (state == STATE_COLLAPSED) {
      top = this.collapsedOffset;
    } else if (state == STATE_HALF_EXPANDED) {
      top = this.halfExpandedOffset;
      if (this.fitToContents && top <= this.fitToContentsOffset) {
        state = STATE_EXPANDED;
        top = this.fitToContentsOffset;
      }
    } else if (state == STATE_EXPANDED) {
      top = this.getExpandedOffset();
    } else {
      if (!this.hideable || state != STATE_HIDDEN) {
        throw new IllegalArgumentException("Illegal state argument: " + state);
      }

      top = this.parentHeight;
    }

    if (this.viewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
      this.setStateInternal(STATE_SETTLING);
      ViewCompat.postOnAnimation(child, new MyTestBehaivor.SettleRunnable(child, state));
    } else {
      this.setStateInternal(state);
    }

  }

  void dispatchOnSlide(int top) {
    View bottomSheet = (View) this.viewRef.get();
    if (bottomSheet != null && this.callback != null) {
      if (top > this.collapsedOffset) {
        this.callback.onSlide(bottomSheet,
            (float) (this.collapsedOffset - top) / (float) (this.parentHeight
                - this.collapsedOffset));
      } else {
        this.callback.onSlide(bottomSheet,
            (float) (this.collapsedOffset - top) / (float) (this.collapsedOffset - this
                .getExpandedOffset()));
      }
    }

  }

  @VisibleForTesting
  int getPeekHeightMin() {
    return this.peekHeightMin;
  }

  public static <V extends View> MyTestBehaivor<V> from(V view) {
    LayoutParams params = view.getLayoutParams();
    if (!(params instanceof android.support.design.widget.CoordinatorLayout.LayoutParams)) {
      throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
    } else {
      Behavior behavior = ((android.support.design.widget.CoordinatorLayout.LayoutParams) params)
          .getBehavior();
      if (!(behavior instanceof MyTestBehaivor)) {
        throw new IllegalArgumentException("The view is not associated with BottomSheetBehavior");
      } else {
        return (MyTestBehaivor) behavior;
      }
    }
  }

  private void updateImportantForAccessibility(boolean expanded) {
    if (this.viewRef != null) {
      ViewParent viewParent = ((View) this.viewRef.get()).getParent();
      if (viewParent instanceof CoordinatorLayout) {
        CoordinatorLayout parent = (CoordinatorLayout) viewParent;
        int childCount = parent.getChildCount();
        if (VERSION.SDK_INT >= 16 && expanded) {
          if (this.importantForAccessibilityMap != null) {
            return;
          }

          this.importantForAccessibilityMap = new HashMap(childCount);
        }

        for (int i = 0; i < childCount; ++i) {
          View child = parent.getChildAt(i);
          if (child != this.viewRef.get()) {
            if (!expanded) {
              if (this.importantForAccessibilityMap != null && this.importantForAccessibilityMap
                  .containsKey(child)) {
                ViewCompat.setImportantForAccessibility(child,
                    (Integer) this.importantForAccessibilityMap.get(child));
              }
            } else {
              if (VERSION.SDK_INT >= 16) {
                this.importantForAccessibilityMap.put(child, child.getImportantForAccessibility());
              }

              ViewCompat.setImportantForAccessibility(child, STATE_COLLAPSED);
            }
          }
        }

        if (!expanded) {
          this.importantForAccessibilityMap = null;
        }

      }
    }
  }

  protected static class SavedState extends AbsSavedState {

    final int state;
    public static final Creator<MyTestBehaivor.SavedState> CREATOR = new ClassLoaderCreator<MyTestBehaivor.SavedState>() {
      public MyTestBehaivor.SavedState createFromParcel(Parcel in, ClassLoader loader) {
        return new MyTestBehaivor.SavedState(in, loader);
      }

      public MyTestBehaivor.SavedState createFromParcel(Parcel in) {
        return new MyTestBehaivor.SavedState(in, (ClassLoader) null);
      }

      public MyTestBehaivor.SavedState[] newArray(int size) {
        return new MyTestBehaivor.SavedState[size];
      }
    };

    public SavedState(Parcel source) {
      this(source, (ClassLoader) null);
    }

    public SavedState(Parcel source, ClassLoader loader) {
      super(source, loader);
      this.state = source.readInt();
    }

    public SavedState(Parcelable superState, int state) {
      super(superState);
      this.state = state;
    }

    public void writeToParcel(Parcel out, int flags) {
      super.writeToParcel(out, flags);
      out.writeInt(this.state);
    }
  }


  private class SettleRunnable implements Runnable {

    private final View view;
    private final int targetState;

    SettleRunnable(View view, int targetState) {
      this.view = view;
      this.targetState = targetState;
    }

    public void run() {
      if (MyTestBehaivor.this.viewDragHelper != null && MyTestBehaivor.this.viewDragHelper
          .continueSettling(true)) {
        ViewCompat.postOnAnimation(this.view, this);
      } else {
        MyTestBehaivor.this.setStateInternal(this.targetState);
      }

    }
  }

  @Retention(RetentionPolicy.SOURCE)
  @RestrictTo({Scope.LIBRARY_GROUP})
  public @interface State {

  }

  public abstract static class BottomSheetCallback {

    public BottomSheetCallback() {
    }

    public abstract void onStateChanged(@NonNull View var1, int var2);

    public abstract void onSlide(@NonNull View var1, float var2);
  }
}
